// Kony


#include "Actor/BaseEffectActor.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystemComponent.h"
#include "AbilitySystem/BaseAttributeSet.h"
#include "Components/SphereComponent.h"
#include "Engine/World.h"
#include "TimerManager.h"



/**
 * 这个Actor 实现了一个物理碰撞触发器，当玩家进入这个Actor的碰撞范围时，会触发OnOverlap函数
 * 出发后获取到碰撞物体的Actor指针获取到对应的UBaseAttributeSet 数据集 来处理属性数据，demo实现了一个血瓶，角色碰撞后回血
 ***/
ABaseEffectActor::ABaseEffectActor()
{
 	PrimaryActorTick.bCanEverTick = false; // 关闭Tick，使用Timer替代
	//设置根组件 允许蓝图设置想要的任意物体碰撞体
	SetRootComponent(CreateDefaultSubobject<USphereComponent>("SceneRoot"));
}
 

void ABaseEffectActor::BeginPlay()
{
	Super::BeginPlay();
	
}

void ABaseEffectActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	// 清理Timer
	if (GetWorld() && FlyToPlayerTimerHandle.IsValid())
	{
		GetWorld()->GetTimerManager().ClearTimer(FlyToPlayerTimerHandle);
	}
	
	Super::EndPlay(EndPlayReason);
}

void ABaseEffectActor::UpdateFlyToPlayer()
{
	// 如果正在飞向玩家
	if (bIsFlyingToPlayer && TargetPlayer.IsValid())
	{
		// 计算到目标玩家的方向和距离
		FVector CurrentLocation = GetActorLocation();
		FVector TargetLocation = TargetPlayer->GetActorLocation();
		FVector Direction = (TargetLocation - CurrentLocation).GetSafeNormal();
		float Distance = FVector::Dist(CurrentLocation, TargetLocation);

		// 如果距离足够近，清除Timer并销毁Actor
		if (Distance <= MinDistanceToPlayer)
		{
			GetWorld()->GetTimerManager().ClearTimer(FlyToPlayerTimerHandle);
			Destroy();
			return;
		}

		// 移动向目标玩家，使用Timer更新频率作为DeltaTime
		FVector NewLocation = CurrentLocation + Direction * FlySpeed * FlyUpdateRate;
		SetActorLocation(NewLocation);
	}
	else
	{
		// 如果目标无效，清除Timer
		GetWorld()->GetTimerManager().ClearTimer(FlyToPlayerTimerHandle);
	}
}
//应用效果到目标Actor,此函数用于蓝图调用 设置目标Actor物体的效果属性数据
void ABaseEffectActor::ApplyEffectToActor(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{
	//获取到目标对象的IAbilitySystemInterface
	// IAbilitySystemInterface* ASCInterface = Cast<IAbilitySystemInterface>(Target);
	// if (ASCInterface)
	// {
	// 	//获取到AbilitySystemComponent
	// 	ASCInterface->GetAbilitySystemComponent();
	// }
	
	//判断如果目标是敌人，并且当前效果设置敌人不生效 则直接返回
	if (TargetActor->ActorHasTag(FName("Enemy")) && !bApplyOnEffectEnemy) return;
	// 通过UAbilitySystemBlueprintLibrary工具类从蓝图中获取目标Actor的AbilitySystemComponent
	// 这是另一种获取AbilitySystemComponent的方式，与上面通过接口获取的方式功能相同,这种只能通过蓝图 上面可以让所有都获取到
	UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);
	if (TargetASC==nullptr) return;
	check(GameplayEffectClass);
	//创建游戏效果 上下文处理器 (处理器是轻量级包装器，可以存储一些指针 比如火焰、冰冻、闪电、毒素等等)
	//用于存储效果相关的上下文信息（如施法者、目标等）
	FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();
	//添加处理器的来源对象
	EffectContextHandle.AddSourceObject(this);
	// 创建游戏效果规格处理器 存储到本地，用于描述游戏效果的详细参数
	// GameplayEffectClass: 要应用的游戏效果类	// ActorLevel: 物品等级	// EffectContextHandle: 效果上下文信息
	const FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, ActorLevel, EffectContextHandle);
	//对自己应用效果ToSelf (还有其他的目标可设置) 存储到 当前活动效果处理
	const FActiveGameplayEffectHandle ActiveEffectHandle = TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get());
	
	//检查效果是否是无限时间的效果,这个判断和存储 主要用于移除无限时间效果
	const bool bIsInfinite = EffectSpecHandle.Data.Get()->Def.Get()->DurationPolicy == EGameplayEffectDurationType::Infinite;
	if (bIsInfinite && InfiniteEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap)
	{
		//如果效果是无限时间效果，那么就把效果处理和目标能力系统组件 添加到本地存储中 
		ActiveEffectHandles.Add(ActiveEffectHandle,TargetASC);
	}
	const bool bHasDuration = EffectSpecHandle.Data.Get()->Def.Get()->DurationPolicy == EGameplayEffectDurationType::HasDuration;
	if (bHasDuration){
		if (TargetASC)
		{
			// 获取AttributeSet
			const UBaseAttributeSet* BaseAttributeSet = Cast<UBaseAttributeSet>(
				TargetASC->GetAttributeSet(UBaseAttributeSet::StaticClass()));
			UBaseAttributeSet* MutableBaseAttributeSet = const_cast<UBaseAttributeSet*>(BaseAttributeSet);

			if (MutableBaseAttributeSet)
			{
				// 检查效果是否影响 Health 或 Mana 属性
				const TArray<FGameplayModifierInfo>& ModifierInfos = EffectSpecHandle.Data->Def.Get()->Modifiers;
				bool bAffectsHealthOrMana = false;
				for (const FGameplayModifierInfo& ModifierInfo : ModifierInfos)
				{
					if (ModifierInfo.Attribute == UBaseAttributeSet::GetHealthAttribute() || 
						ModifierInfo.Attribute == UBaseAttributeSet::GetManaAttribute())
					{
						bAffectsHealthOrMana = true;
						break;
					}
				}
				
				// 只有影响 Health 或 Mana 的效果才调用 SetGhost
				if (bAffectsHealthOrMana)
				{
					MutableBaseAttributeSet->SetGhost(EffectSpecHandle);
				}
			}
		}
	}
	//注意：幽灵血条会在BaseAttributeSet的PostGameplayEffectExecute中自动处理
	//当应用持续恢复效果时，幽灵血条会立即设置为最终恢复到的值
	//这样UI就能显示幽灵血条缓慢跟随的效果
	
	//注意：幽灵血球跟随控制现在通过蓝图手动设置
	//在蓝图中调用 SetGhostHealthBarFollowing(false) 来禁用跟随
	//在效果结束后调用 SetGhostHealthBarFollowing(true) 来重新启用跟随
	
	//检查如果设置了应用时销毁，并且是即时效果 则应用时销毁
	if (bDestroyOnEffectRemovel && !bIsInfinite)
	{
		// 如果启用了飞向玩家功能
		if (bEnableFlyToPlayer)
		{
			// 设置目标玩家并开始飞行
			TargetPlayer = TargetActor;
			bIsFlyingToPlayer = true;
			// 启动Timer定时更新飞向玩家的逻辑
			GetWorld()->GetTimerManager().SetTimer(FlyToPlayerTimerHandle, this, &ABaseEffectActor::UpdateFlyToPlayer, FlyUpdateRate, true);
		}
		else
		{
			// 直接销毁
			Destroy();
		}
	}
}

void ABaseEffectActor::OnOverlap(AActor* TargetActor)
{
	//判断如果目标是敌人，并且当前效果设置敌人不生效 则直接返回
	if (TargetActor->ActorHasTag(FName("Enemy")) && !bApplyOnEffectEnemy) return;
	//重叠时 如果即时生效效果，设置的是应用效果
	if (InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap)
	{
		//则执行即使时间类型效果
		ApplyEffectToActor(TargetActor, InstantGameplayEffectClass); 
	}
	//重叠时 如果持续生效效果，设置的是应用效果
	if (DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap)
	{
		//则执行持续时间类型效果
		ApplyEffectToActor(TargetActor, DurationGameplayEffectClass);
	}
	//重叠时 如果无线时间效果，设置的是应用效果
	if (InfiniteEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap)
	{
		ApplyEffectToActor(TargetActor, InfiniteGameplayEffectClass);
	}
}

void ABaseEffectActor::OnEndOverlap(AActor* TargetActor)
{
	//判断如果目标是敌人，并且当前效果设置敌人不生效 则直接返回
	if (TargetActor->ActorHasTag(FName("Enemy")) && !bApplyOnEffectEnemy) return;
	//如果结束重叠时触发 即时生效效果，设置的是应用效果
	if (InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap)
	{
		ApplyEffectToActor(TargetActor, InstantGameplayEffectClass);
	}
	//如果结束重叠时触发 持续生效效果，设置的是应用效果
	if (InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap)
	{
		ApplyEffectToActor(TargetActor, DurationGameplayEffectClass);
	}
	//如果结束重叠时触发 无线时间效果，设置的是应用效果
	if (InfiniteEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap)
	{
		ApplyEffectToActor(TargetActor, InfiniteGameplayEffectClass);
	}
	//如果无限时间设置的是 重叠结束时移除效果
	if (InfiniteEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap)
	{
		UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);
		if (!IsValid(TargetASC)) return;

		TArray<FActiveGameplayEffectHandle> HandlesToRemove;
		for (TTuple<FActiveGameplayEffectHandle, UAbilitySystemComponent*> HandlePair : ActiveEffectHandles)
		{
			if (TargetASC == HandlePair.Value)
			{
				//移除效果 StacksToRemove 如果为-1 表示移除所有堆叠
				TargetASC->RemoveActiveGameplayEffect(HandlePair.Key, 1);
				//将这个效果存储到本地数组
				HandlesToRemove.Add(HandlePair.Key);
			}
		}
		for (FActiveGameplayEffectHandle& Handle : HandlesToRemove)
		{
			//移除已经完成的效果处理 避免死循环
			ActiveEffectHandles.FindAndRemoveChecked(Handle);
		}
	}
}
 
